/*
Name: StrCalc.c
Copyright: Exinferis Inc.- 1999-2006
URL: http://www.inexinferis.co.nr
Author: Karman
Date: 12/05/05 15:13
Version: 0.95
Description: Calculadora de Strings...
Operandos:
Enteros, Reales y ()
Operaciones Permitidas:
Matemáticas:
+ - / * % ^
Funciones:
asin(x) - ArcoSeno
acos(x) - ArcoCoseno
atan(x) - ArcoTangente
abs(x) - Absoluto (+)
sin(x) - Seno
sinh(x) - Seno hiperbólico
cos(x) - Coseno
cosh(x) - Coseno hiperbólico
tan(x) - Tangente
tanh(x) - Tangente hiperbólica
ln(x) - Logaritmo natural
log(x) - Logaritmo base 10
e(x) - e a la n
rand(x) - Número aleatorio
rnd(x) - Redondeo
int(x) - Truncado a entero
Example:
Calculate("2^5/(2*8)+9^(1/2)-(ln(e(1)))*(cos(90)-sin(90))");
*/
#include "strcalc.h"
//Modo radianes (rad=1) modo normal (rad=0)
char rad=0;
char *fstart=0,*errpos=0;
//Funciones válidas
FUNC func[]={
{"asin(",'a'},{"acos(",'b'},{"atan(",'d'},{"abs(",'j'},{"sin(",'s'},
{"sinh(",'f'},{"cos(",'c'},{"cosh(",'g'},{"tan(",'t'},{"tanh(",'h'},
{"ln(",'n'},{"log(",'l'},{"e(",'e'},{"rand(",'r'},{"rnd(",'u'},{"int(",'i'}
};
//********************************************************
// Devuelve la posición del error... (si hubo alguno)
//********************************************************
unsigned char GetFunctionErrorPos(void){
return (unsigned char)(errpos-fstart);
}
//********************************************************
// Devuelve el error... (si hubo alguno)
//********************************************************
char *GetFunctionError(void){
return errpos;
}
//********************************************************
// Libera lista en caso de error...
//********************************************************
void freelist(PCALCS prim){
PCALCS tmp;
while(prim){
tmp=prim;prim=prim->sig;free(tmp);
}
}
//********************************************************
// Calcula lista de operaciones-operandos...
//********************************************************
double CalcOp(PCALCS pcy){
double res=0;PCALCS tpcy;
while(pcy){
switch(pcy->op){
case '=':res=pcy->val;break;
case '^':res=pow(res,pcy->val);break;
case '%':res=fmod(res,pcy->val);break;
case '*':res=res*pcy->val;break;
case '/':res=res/pcy->val;break;
case '+':res=res+pcy->val;break;
case '-':res=res-pcy->val;break;
//Arc trig. functions
case 'a':
if(rad)res=asin(pcy->val);
else res=(asin(pcy->val)*180)/M_PI;
break;
case 'b':
if(rad)res=acos(pcy->val);
else res=(acos(pcy->val)*180)/M_PI;
break;
case 'd':
if(rad)res=atan(pcy->val);
else res=(atan(pcy->val)*180)/M_PI;
break;
//Trig. Functions
case 's':
if(rad)res=sin(pcy->val);
else res=sin((pcy->val*M_PI)/180);
break;
case 'c':
if(rad)res=cos(pcy->val);
else res=cos((pcy->val*M_PI)/180);
break;
case 't':
if(rad)res=tan(pcy->val);
else res=tan((pcy->val*M_PI)/180);
break;
//Hip. Functions
case 'f':res=sinh(pcy->val);break;
case 'g':res=cosh(pcy->val);break;
case 'h':res=tanh(pcy->val);break;
//Other functions
case 'n':res=log(pcy->val);break;
case 'l':res=log10(pcy->val);break;
case 'e':res=exp(pcy->val);break;
case 'j':res=fabs(pcy->val);break;
case 'r':res=fmod(rand(),pcy->val);break;
case 'i':modf(pcy->val,&res);break;
case 'u':res=ceill(pcy->val);break;
default:res=0;
}
tpcy=pcy;pcy=pcy->sig;free(tpcy);
}
return res;
}
//********************************************************
// Obtiene el número del String...
//********************************************************
double GetNum(char **txt){
double tmp=0;unsigned char des=0;
while((**txt)&&(isdigit(**txt)||((**txt)=='.')||((**txt)==' '))){
//Controlamos espacios en blanco...
if(**txt==' '){
while(**txt==' ')(*txt)++;
continue;
}
if((**txt)=='.')
if(des){
errpos=*txt;
return 0;
}else{
des=1;
(*txt)++;
continue;
}
if(des)
tmp=tmp+((*((*txt)++)-0x30)/pow(10,des++));
else
tmp=(tmp*10)+(*((*txt)++)-0x30);
}
if(des&&tmp==0){
errpos=*txt;
return 0;
}
else return tmp;
}
//********************************************************
// Genera lista de Operadores-Operandos y administra
// resultados... (recursivo)
//********************************************************
static double Calc(char **py,char lop,double lval){
char *pyt,*opy,cp,trig,tmp[256];
unsigned char av,flen,nfunc=sizeof(func)/sizeof(func[0]);
PCALCS prim=NULL,tp=NULL,atp=NULL,tq,tt;
while(**py){
//Controlamos espacios en blanco...
while(**py==' ')*py++;
//Nuevo elemento...
if(tp)atp=tp;
tp=(PCALCS)malloc(sizeof(CALCS));
if(!prim)prim=tp;else tq->sig=tp;
tq=tp;tp->sig=NULL;
//Operación?
if(lval){//Argumento enviado...
tp->val=lval;tp->op='=';lval=0;continue;
}
//primer operación...
if(isoper(**py))//Es una operación?
switch(**py){
//Suma Resta prioridad 3...
case '+':case '-':
switch(lop){
case '*':case '^':case '%':
atp->sig=NULL;free(tp);
return CalcOp(prim);
case '+':
tp->op=*(*py)++;
break;
default:
goto OnError;//Error...
}
break;
//Multiplicación Divición prioridad 2...
case '*':case '/':
switch(lop){
case '^':case '%':
atp->sig=NULL;free(tp);
return CalcOp(prim);
case '*':tp->op=*(*py)++;break;
case '+':
atp->val=Calc(&(*py),'*',atp->val);
atp->sig=NULL;free(tp);tp=NULL;tq=atp;
if(errpos!=fstart)
goto OnError;//Error...
continue;
default:
goto OnError;//Error...
}
break;
//Modulo prioridad 1...
case '%':
switch(lop){
case '^':
atp->sig=NULL;free(tp);
return CalcOp(prim);
case '%':tp->op=*(*py)++;break;
case '+':case '*':
atp->val=Calc(&(*py),'%',atp->val);
atp->sig=NULL;free(tp);tp=NULL;tq=atp;
if(errpos!=fstart)
goto OnError;//Error...
continue;
default:
goto OnError;//Error...
}
break;
//Potencia prioridad 0...
case '^':
switch(lop){
case '^':tp->op=*(*py)++;break;
case '+':case '*':case '%':
atp->val=Calc(&(*py),'^',atp->val);
atp->sig=NULL;free(tp);tp=NULL;tq=atp;
if(errpos!=fstart)
goto OnError;//Error...
continue;
default:
goto OnError;//Error...
}
break;
default:
goto OnError;//Error...
}
else //Restantes opciones...
tp->op='=';
//Obtenemos argumento...
if(isdigit(**py)||((**py)=='.')){
tp->val=GetNum(&(*py));
if(errpos!=fstart)
goto OnError;//Error...
}else{
trig=0;
//Parentesis...
if(**py=='(')goto CalcCont;
//Funciones...
for(av=0;av<nfunc;av++){
flen=strlen(func[av].fname);
if(!strncmp(*py,func[av].fname,flen)){
(*py)+=flen-1;trig=func[av].func;
goto CalcCont;
}
}
//Tratamos Error...
goto OnError;//Error...
CalcCont://Calculamos contenido de "()"
pyt=tmp;cp=1;(*py)++;opy=*py;
while(**py){
if(**py=='(')++cp;
if(**py==')')--cp;
if(!cp)break;
*(pyt++)=*(*py)++;
}
if(cp)
goto OnError;//Error...
*pyt=0;(*py)++;pyt=tmp;
tp->val=Calc(&pyt,'+',0);
if(errpos!=fstart){
*py=opy;
goto OnError;//Error...
}
//Resolvemos funciones...
if(trig){
tt=(PCALCS)malloc(sizeof(CALCS));
tt->sig=NULL;
tt->op=trig;
tt->val=tp->val;
tp->val=CalcOp(tt);
}
}
}
return CalcOp(prim);
OnError://Error...
errpos=*py;
freelist(prim);
return 0;
}
//********************************************************
// Verifica String y llama a la función de cálculo...
//********************************************************
double Calculate(char *arg){
fstart=errpos=arg;
if(strlen(arg)>256){//256 caracteres Máximo...
errpos=arg+256;
return 0;
}
return Calc(&arg,'+',0);
}